﻿
Imports System.Runtime.CompilerServices
Imports osi.root.constants

Public Module _strindexof
    Private Delegate Function indexDelegate(ByVal s As String, ByVal search As String, ByRef start As Int64) As Int64

    'will fail in some properly not valid characters
    Private Function strindexofImpl(ByVal s As String, ByVal search As String, ByRef start As Int64) As Int64
        Dim rtn As Int64 = 0
        rtn = s.IndexOf(search, Convert.ToInt32(start))
        start = rtn + strlen(search)

        Return rtn
    End Function

    Private Function strlastindexofImpl(ByVal s As String, ByVal search As String, ByRef start As Int64) As Int64
        Dim rtn As Int64 = 0
        rtn = s.LastIndexOf(search, Convert.ToInt32(start))
        start = rtn - strlen(search)

        Return rtn
    End Function

    Private Function strindexofImpl(ByVal s As String, ByVal search As String, ByVal start As Int64, _
                                    ByVal indexOfIndex As Int64, ByVal indexcall As indexDelegate, _
                                    ByVal carecase As Boolean) As Int64
        If String.IsNullOrEmpty(search) Then
            Return 0
        ElseIf String.IsNullOrEmpty(s) Then
            Return npos
        ElseIf indexOfIndex <= 0 Then
            Return 0
        ElseIf start < 0 OrElse start >= strlen(s) Then
            Return npos
        Else
            If Not carecase Then
                s = s.ToLower()
                search = search.ToLower()
            End If
            Dim searchlen As Int32 = 0
            searchlen = strlen(search)
            Dim rtn As Int32 = 0
            Dim nextSearch As Int64 = 0
            nextSearch = start
            Dim i As Int64 = 0
            For i = 0 To indexOfIndex - 1
                rtn = indexcall(s, search, nextSearch)
                If rtn = npos Then
                    Exit For
                ElseIf (nextSearch < 0 OrElse nextSearch >= strlen(s)) AndAlso i < indexOfIndex - 1 Then
                    'cannot search for one more time, so the rtn should be npos
                    rtn = npos
                    Exit For
                End If
            Next

            Return rtn
        End If
    End Function

    <Extension()> Public Function strindexof(ByVal s As String, ByVal search As String,
                                             Optional ByVal carecase As Boolean = True) As Int64
        Return strindexof(s, search, 1, carecase)
    End Function

    <Extension()> Public Function strindexof(ByVal s As String, ByVal search As String, ByVal indexOfIndex As Int64,
                                             Optional ByVal carecase As Boolean = True) As Int64
        Return strindexof(s, search, 0, indexOfIndex, carecase)
    End Function

    <Extension()> Public Function strindexof(ByVal s As String,
                                             ByVal search As String,
                                             ByVal start As Int64,
                                             ByVal indexOfIndex As Int64,
                                             Optional ByVal carecase As Boolean = True) As Int64
        Return strindexofImpl(s, search, start, indexOfIndex, AddressOf strindexofImpl, carecase)
    End Function

    <Extension()> Public Function strlastindexof(ByVal s As String, ByVal search As String,
                                                 Optional ByVal carecase As Boolean = True) As Int64
        Return strlastindexof(s, search, 1, carecase)
    End Function

    <Extension()> Public Function strlastindexof(ByVal s As String,
                                                 ByVal search As String,
                                                 ByVal indexOfIndex As Int64,
                                                 Optional ByVal carecase As Boolean = True) As Int64
        Return strlastindexof(s, search, strlen(s) - 1, indexOfIndex, carecase)
    End Function

    <Extension()> Public Function strlastindexof(ByVal s As String,
                                                 ByVal search As String,
                                                 ByVal start As Int64,
                                                 ByVal indexOfIndex As Int64,
                                                 Optional ByVal carecase As Boolean = True) As Int64
        Return strindexofImpl(s, search, start, indexOfIndex, AddressOf strlastindexofImpl, carecase)
    End Function
End Module
